using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Tile_Engine;
using Ziggyware;
using Shadows2D;
using System.IO;
using AGrandVenture.Dungen;

namespace AGrandVenture
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        private bool USE_DUNGEN = true;

        public enum GameState { Intro, Title, Menu, Playing, Paused  };
        public GameState gameState = GameState.Playing;
        public bool startButtonToggle = false;
        public Player player;    

        public const int _SCREEN_WIDTH = 1280;
        public const int _SCREEN_HEIGHT = 720;
        public const bool _IS_FULL_SCREEN = false;

        GraphicsDeviceManager graphics;
        private static QuadRenderComponent quadRender;
        RenderTarget2D screenShadows;
        SpriteBatch spriteBatch;
        const int maxShadowQuality = 8;
        const int shadowDepth = 10;

        public static Texture2D playerTexture;
        public static Texture2D gameTextures;
        public static Texture2D effectsSheet;
        public static Texture2D enemyGeneratorSheet;
        public static Texture2D bugOctoSheet;
        public static Texture2D evilEyeSheet;
        public static Texture2D slimeEyeSheet;
        public static Texture2D whiteDotSheet;
        public static Texture2D lootSheet;
        public static Texture2D resourceSheet;
        public static Texture2D equipmentSheet;
        public static Texture2D attackSlashSheet;
        public static Texture2D pauseScreen;
        public static Texture2D inventoryItemFrame;
        public static Texture2D selectedInventoryItemFrame;
        public static Texture2D menuChoiceBubble;
        public static Texture2D selectedMenuChoiceBubble;
        public static Texture2D selectedSubmenuFrame;
        public static Texture2D submenuFrame;
        public static Texture2D selectedItemWhirl;
        public static Texture2D equippedItemFrame;
        public static Texture2D selectedItemInfoFrame;

        public static SpriteFont fontPericles8;
        public static SpriteFont fontMiramonte12;
        public static SpriteFont fontSegoe14;
        public static SpriteFont fontLucida12;
        public static SpriteFont fontFranklin14;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            Components.Add(new InputHandler(this)); //add input handler
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            this.graphics.PreferredBackBufferWidth = _SCREEN_WIDTH;
            this.graphics.PreferredBackBufferHeight = _SCREEN_HEIGHT;
            this.graphics.IsFullScreen = _IS_FULL_SCREEN;
            this.graphics.ApplyChanges();

            //Shadow2d
            quadRender = new QuadRenderComponent(this);
            this.Components.Add(quadRender);
            //End Shadow2d

            if (USE_DUNGEN)
                DungeonGenerator.Initialise(TileMap.MapWidth, TileMap.MapHeight);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // Textures
            effectsSheet = Content.Load<Texture2D>(@"Textures\effectsSheet48x48");
            enemyGeneratorSheet = Content.Load<Texture2D>(@"Textures\enemyGeneratorSheet");
            bugOctoSheet = Content.Load<Texture2D>(@"Textures\enemysheet2");
            evilEyeSheet = Content.Load<Texture2D>(@"Textures\evileye");
            slimeEyeSheet = Content.Load<Texture2D>(@"Textures\slimeeyes");
            lootSheet = Content.Load<Texture2D>(@"Textures\GemSheet");
            whiteDotSheet = Content.Load<Texture2D>(@"Textures\WhiteDot");
            playerTexture = Content.Load<Texture2D>(@"Textures\player48x48");
            resourceSheet = Content.Load<Texture2D>(@"Textures\mineralVein");
            equipmentSheet = Content.Load<Texture2D>(@"Textures\Equipment");
            attackSlashSheet = Content.Load<Texture2D>(@"Textures\attackSlashSheet");
            pauseScreen = Content.Load<Texture2D>(@"Screens\InventoryScreen");
            selectedInventoryItemFrame = Content.Load<Texture2D>(@"Textures\SelectedInventoryItemFrame");
            inventoryItemFrame = Content.Load<Texture2D>(@"Textures\InventoryItemFrame");
            menuChoiceBubble = Content.Load<Texture2D>(@"Textures\MenuChoiceBubble");
            selectedMenuChoiceBubble = Content.Load<Texture2D>(@"Textures\SelectedMenuChoiceBubble");
            selectedSubmenuFrame = Content.Load<Texture2D>(@"Textures\SelectedSubmenuFrame");
            submenuFrame = Content.Load<Texture2D>(@"Textures\SubmenuFrame");
            selectedItemWhirl = Content.Load<Texture2D>(@"Textures\SelectedWhirl");
            equippedItemFrame = Content.Load<Texture2D>(@"Textures\EquippedItemFrame");
            selectedItemInfoFrame = Content.Load<Texture2D>(@"Textures\SelectedItemInfoFrame");

            //Fonts
            fontPericles8 = Content.Load<SpriteFont>(@"Fonts\Pericles8");
            fontMiramonte12 = Content.Load<SpriteFont>(@"Fonts\Miramonte12");
            fontSegoe14 = Content.Load<SpriteFont>(@"Fonts\SegoeUI14");
            fontLucida12 = Content.Load<SpriteFont>(@"Fonts\LucidaCalligraphy12");
            fontFranklin14 = Content.Load<SpriteFont>(@"Fonts\FranklinGothic14");

            if (USE_DUNGEN)
                TileMap.Initialize(Content.Load<Texture2D>(@"Textures\DunGenTileSheet_v1.4"));
            else
                TileMap.Initialize(Content.Load<Texture2D>(@"Textures\tileSheet"));
            TileMap.spriteFont = Content.Load<SpriteFont>(@"Fonts\Pericles8");

            //Load textual data
            DataManager.Initialise(this.Content);

            //Shadow2d
            ShadowmapResolver shadowmapResolver = new ShadowmapResolver(GraphicsDevice, quadRender, maxShadowQuality, shadowDepth);
            shadowmapResolver.LoadContent(Content);
            LightManager.Initialize(this, shadowmapResolver, quadRender, GraphicsDevice);
            //End Shadow2d

            Camera.WorldRectangle = new Rectangle(0, 0, (TileMap.MapWidth * TileMap.TileWidth), (TileMap.MapHeight * TileMap.TileHeight));
            Camera.ViewPortWidth = _SCREEN_WIDTH;
            Camera.ViewPortHeight = _SCREEN_HEIGHT;

            player = new Player();
            //set Player Start
            Vector2 playerStart;
            if(USE_DUNGEN)
                playerStart = new Vector2((TileMap.MapWidth / 2 + 1) * TileMap.TileWidth, (TileMap.MapHeight / 2 + 1) * TileMap.TileHeight);                
            else
                playerStart = new Vector2(1,1);

            Player.Initialise(
                playerTexture,
                new Rectangle(0, 0, 48, 48),
                6,
                new Rectangle(48, 0, 48, 48),
                1,
                playerStart);

            LightManager.addLightSource(Player.BaseSprite, Color.White, .6, true);

            //center camera on player.
            Camera.Position = new Vector2((Player.WorldLocation.X - (_SCREEN_WIDTH / 2)), (Player.WorldLocation.Y - (_SCREEN_HEIGHT / 2)));

            WeaponManager.Texture = effectsSheet;

            EffectsManager.Initialize(effectsSheet, new Rectangle(0, 0, 1, 1), new Rectangle(0, 0, 1, 1), 1);

            GoalManager.Initialise(enemyGeneratorSheet, new Rectangle(0, 0, 48, 48), new Rectangle(288, 0, 48, 48), 5, 1);

            //TileMap.GenerateRandomMap();
            //LevelManager.GenerateRandomResources();

            GoalManager.GenerateEnemyGenerators(0); //this needs to be moved - part of level initialisation

            MessageWindow.Initialise(fontPericles8, new Vector2(5, _SCREEN_HEIGHT - 5), 10.0f, 10, Color.Yellow);

            if (USE_DUNGEN)
            {
                DungeonGenerator.MakeLevel();
                TileMap.Darkness = 0.5f;

                DungeonSkinner.SkinDungeon(DungeonGenerator.GetMap);
 
                DungeonGenerator.AddMonsterGenerators(2);
                DungeonGenerator.AddChests(5);
                LevelManager.PlaceEnemies();
                LevelManager.PlaceChests();

            }
            else
            {
                LevelManager.LoadLevel(2);
            }

            
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (!startButtonToggle && (InputHandler.KeyPressed(Keys.Enter) || (InputHandler.ButtonPressed(Buttons.Start, PlayerIndex.One))))
                startButtonToggle = true;

            // Allows the game to exit
            if (InputHandler.ButtonPressed(Buttons.Back, PlayerIndex.One))
                this.Exit();
            else if (startButtonToggle && (InputHandler.KeyReleased(Keys.Enter) || InputHandler.ButtonReleased(Buttons.Start, PlayerIndex.One)))
            {
                if (gameState == GameState.Playing)
                {
                    gameState = GameState.Paused;
                    PauseScreenUI.Initialize();
                }
                else if (gameState == GameState.Paused)
                {
                    gameState = GameState.Playing;
                    PauseScreenUI.Suspend();
                }
                startButtonToggle= false;
            }

            if (gameState == GameState.Playing)
            {
                // TODO: Add your update logic here
                Player.Update(gameTime);
                WeaponManager.Update(gameTime);
                EffectsManager.Update(gameTime);
                GoalManager.Update(gameTime);
                EnemyManager.Update(gameTime);
                LootManager.Update(gameTime);
                MessageWindow.Update(gameTime);
                LightManager.Update(gameTime);
            }
            else if (gameState == GameState.Paused)
            {
                PauseScreenUI.handlePauseInput();
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            if (gameState == GameState.Playing)
            {
                //Create shadows, draw ground then all other objects
                screenShadows = LightManager.Draw(GraphicsDevice, spriteBatch);
                DrawGround();
                DrawScene();

                //Blend shadows to total scene
                BlendState blendState = new BlendState();
                blendState.ColorSourceBlend = Blend.DestinationColor;
                blendState.ColorDestinationBlend = Blend.SourceColor;
                spriteBatch.Begin(SpriteSortMode.Immediate, blendState);
                spriteBatch.Draw(screenShadows, Vector2.Zero, Color.White * TileMap.Darkness);
                spriteBatch.End();

                //Draw on-screen interface
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
                DrawUI(spriteBatch);
                spriteBatch.End();
            }
            else if (gameState == GameState.Paused)
            {
                PauseScreenUI.drawPauseMenu(spriteBatch);
                base.Draw(gameTime);
            }
        }

        #region Shadow2D Helper Methods

        public void DrawShadowCasters(Vector2 location, double size)
        {
            spriteBatch.Begin();
            TileMap.DrawShadows(spriteBatch, location, size);
            //EnemyManager.DrawShadows(spriteBatch, location, size); --Just doesn't look right
            spriteBatch.End();
        }

        private void DrawScene()
        {
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
            WeaponManager.Draw(spriteBatch);
            EffectsManager.Draw(spriteBatch);
            GoalManager.Draw(spriteBatch);
            EnemyManager.Draw(spriteBatch);
            LevelManager.Draw(spriteBatch);
            LootManager.Draw(spriteBatch);
            Player.Draw(spriteBatch);
            
            spriteBatch.End();
        }
        private void DrawGround()
        {
            spriteBatch.Begin();
            TileMap.Draw(spriteBatch);
            spriteBatch.End();
        }
        #endregion
        private void DrawUI(SpriteBatch spriteBatch)
        {
            MessageWindow.Draw(spriteBatch);
            spriteBatch.DrawString(fontPericles8, "XP: " + GameManager.XP.ToString(), new Vector2(5, 5), Color.Goldenrod);

            //test data

            spriteBatch.DrawString(fontPericles8, "CameraX:" + (Camera.Position.X / TileMap.TileWidth).ToString() + " CameraY:" + (Camera.Position.Y / TileMap.TileHeight).ToString(), new Vector2(5, 20), Color.White);
            spriteBatch.DrawString(fontPericles8, "PlayerX:" + (Player.WorldLocation.X / TileMap.TileWidth).ToString() + " PlayerY:" + (Player.WorldLocation.Y / TileMap.TileHeight).ToString(), new Vector2(5, 30), Color.White);
            spriteBatch.DrawString(fontPericles8, "Move:" + (Player.MoveAngle.X).ToString() + " MoveY:" + (Player.MoveAngle.Y).ToString(), new Vector2(5, 40), Color.White);
          
            //
        }
        
    }
}
